<?php
/**
 * This file is part of DomAr.
 * 
 * DomAr is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * DomAr is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with DomAr.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * @link http://inditel.ee/
 * @copyright 2007-2009 Inditel Meedia OÜ
 * @author Oliver Leisalu <oliver@inditel.ee>
 */

/**
 * @package DomAr
 * @subpackage Parser
 */
class DomArAnnotationParser {
	
	public static function parse( $annotation, $type, $file, $line ) {
		require(DOM_CONF_DIR_PATH . 'annotations.conf.php' );
		
		$totalFinds = preg_match_all('/@orm/', $annotation, $matches );
		
		$N = 0;
		$return = array();
		$fullAnnotations = array();
		foreach( $DOMAR_ANNOTATIONS[strtoupper($type)] as $annotationConfig ) {
			$regularExpr = &$annotationConfig['syntax'];

			$matches = array();
			try {
				preg_match_all( $regularExpr, $annotation, $matches );
			} catch( RuntimeException $e ) {
				throw new RuntimeException( $e->getMessage().'<b>Failed regularexpression:</b> <br /><pre>'.htmlentities($regularExpr).'</pre> <br /><b>Annotation:</b><br /><pre>'.htmlentities($annotation).'</pre>' );
			}
			foreach( $matches as $key => $values ) {
				if( is_string($key) === true ) {
					if( substr($key,-2,2) == '_f' ) {
						$key = substr($key,0,-2);
						$isArgument = true;
					} else {
						$isArgument = false;
					}
					foreach( $values as $i => $value ) {
						if( $isArgument === true) {
							$value = self::parseFunctionArgument($value);
							$value = $value[0];
						}
						$return[$N+$i]['handler'] = $annotationConfig['handler'];
						$return[$N+$i][$key] = $value;
						$fullAnnotations[$N+$i] = $matches[0][$i];
					}
				}
			}
			$N = count($return);
		}

		if( $N != $totalFinds ) {
			preg_match_all('/@orm(.*)(\r\n|\n){1}/', $annotation, $findAllRules);

			$erroredRules = array();
			foreach( $findAllRules[0] as $match ) {
				if( !in_array($match, $fullAnnotations) ) {
					$erroredRules[] = $match;
				}
			}

			throw new RuntimeException('Failed to parse all <b>@orm</b> annotations in <b>'.$file.'('.$line.')</b> for annotation type <b>'.$type.'</b>. Check these: <br>'.implode('<br>',$erroredRules) );

			//throw new RuntimeException('Check your annotations. Found '.$totalFinds.' @orm tags but matched only '.$N.' rules. <br> Annotation: <br> '.str_replace("\n",'<br>',$annotation));
		}

		return $return;
	}	
	
	private static function parseFunctionArgument( $var ) {

		$length = strlen($var);
		$result = array();
		$argumentNr = 0;
		$lastKey = 0;
		for( $i=0; $i<$length; $i++) {
			if( $var{$i} == '{' or $var{$i} == '[') {
				list($result[$lastKey], $s) = self::parseFunctionArgument( substr($var, $i+1, $length) );
				$i+=$s;
			} elseif( $var{$i} == '}' or $var{$i} == ']') {
				break;
			} elseif( $var{$i} == ',') {
				if( is_string($result[$lastKey]) )
					$result[$lastKey] = trim($result[$lastKey]);
				$lastKey = ++$argumentNr;
			} elseif( $var{$i} == '=') {
				$s = $result[$lastKey];
				$result[$s] = '';
				unset($result[$lastKey]);
				$result[$s] = trim($result[$lastKey]);
				$lastKey = $s;
				unset($s);
				$argumentNr--;
			} else {
				$result[$lastKey] .= $var{$i};
			}
		}
		
		if( is_string($result[$lastKey]) )
			$result[$lastKey] = trim($result[$lastKey]);

		return array($result, $i+1);
	}
	
}
?>